<div class="tmd-doc">
<h1 class="tmd-header-1">
Memory Blocks
</h1>
<p></p>
<div class="tmd-usual">
Go is a language which supports automatic memory management, such as automatic memory allocation and automatic garbage collection. So Go programmers can do programming without handling the underlying verbose memory management. This not only brings much convenience and saves Go programmers lots of time, but also helps Go programmers avoid many careless bugs.
</div>
<p></p>
<div class="tmd-usual">
Although knowing the underlying memory management implementation details is not necessary for Go programmers to write Go code, understanding some concepts and being aware of some facts in the memory management implementation by the standard Go compiler and runtime is very helpful for Go programmers to write high quality Go code.
</div>
<p></p>
<div class="tmd-usual">
This article will explain some concepts and list some facts of the implementation of memory block allocation and garbage collection by the standard Go compiler and runtime. Other aspects, such as memory apply and memory release in memory management, will not be touched in this article.
</div>
<p></p>
<h3 id="memory-block" class="tmd-header-3">
Memory Blocks
</h3>
<p></p>
<div class="tmd-usual">
A memory block is a continuous memory segment to host <a href="value-part.html">value parts</a> at run time. Different memory blocks may have different sizes, to host different value parts. One memory block may host multiple value parts at the same time, but each value part can only be hosted within one memory block, no matter how large the size of that value part is. In other words, for any value part, it never crosses memory blocks.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
There are many reasons when one memory block may host multiple value parts. Some of them:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
a struct value often have several fields. So when a memory block is allocated for a struct value, the memory block will also host (the direct parts of) these field values.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
an array values often have many elements. So when a memory block is allocated for a array value, the memory block will also host (the direct parts of) the array element values.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
the underlying element sequences of two slices may be hosted on the same memory block, the two element sequences even can overlap with each other.
</div>
</li>
</ul>
<p></p>
<h3 class="tmd-header-3">
A Value References the Memory Blocks Which Host Its Value Parts
</h3>
<p></p>
<div class="tmd-usual">
We have known that a value part can reference another value part. Here, we extend the reference definition by saying a memory block is referenced by all the value parts it hosts. So if a value part <code class="tmd-code-span">v</code> is referenced by another value part, then the other value will also reference the memory block hosting <code class="tmd-code-span">v</code>, indirectly.
</div>
<p></p>
<h3 id="when-to-allocate" class="tmd-header-3">
When Will Memory Blocks Be Allocated?
</h3>
<p></p>
<div class="tmd-usual">
In Go, memory blocks may be allocated but not limited at following situations:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
explicitly call the <code class="tmd-code-span">new</code> and <code class="tmd-code-span">make</code> built-in functions. A <code class="tmd-code-span">new</code> call will always allocate exact one memory block. A <code class="tmd-code-span">make</code> call will allocate more than one memory blocks to host the direct part and underlying part(s) of the created slice, map or channel value.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
create maps, slices and anonymous functions with corresponding literals. More than one memory blocks may be allocated in each of the processes.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
declare variables.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
assign non-interface values to interface values (when the non-interface value is not a pointer value).
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
concatenate non-constant strings.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
convert strings to byte or rune slices, and vice versa, except <a href="string.html#conversion-optimizations">some special compiler optimization cases</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
convert integers to strings.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
call the built-in <code class="tmd-code-span">append</code> function (when the capacity of the base slice is not large enough).
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
add a new key-element entry pair into a map (when the underlying hash table needs to be resized).
</div>
</li>
</ul>
<p></p>
<p></p>
<h3 id="where-to-allocate" class="tmd-header-3">
Where Will Memory Blocks Be Allocated On?
</h3>
<p></p>
<div class="tmd-usual">
For every Go program compiled by the official standard Go compiler, at run time, each goroutine will maintain a stack, which is a memory segment. It acts as a memory pool for some memory blocks to be allocated from/on. Before Go Toolchain 1.19, the initial size of a stack is always 8KiB on Windows platform and 2KiB on other platforms. Since Go Toolchain 1.19, the initial size is <a href="https://docs.google.com/document/d/1YDlGIdVTPnmUiTAavlZxBI1d9pwGQgZT7IKFKlIXohQ">adaptive</a>. The stack of a goroutine will grow and shrink as needed in goroutine running. The minimum stack size is 8KiB on Windows platform and 2KiB on other platforms.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
<span class="tmd-italic">(Please note, there is a global limit of stack size each goroutine may reach. If a goroutine exceeds the limit while growing its stack, the program crashes. As of Go Toolchain 1.25.n, the default maximum stack size is 1 GB on 64-bit systems, and 250 MB on 32-bit systems. We can call the <code class="tmd-code-span">SetMaxStack</code> function in the <code class="tmd-code-span">runtime/debug</code> standard package to change the size. And please note that, by the current official standard Go compiler implementation, the actual allowed maximum stack size is the largest power of 2 which is not larger than then MaxStack setting. So for the default setting, the actual allowed maximum stack size is 512 MiB on 64-bit systems, and 128 MiB on 32-bit systems.)</span>
</div>
<p></p>
<div class="tmd-usual">
Memory blocks can be allocated on stacks. Memory blocks allocated on the stack of a goroutine can only be used (referenced) in the goroutine internally. They are goroutine localized resources. They are not safe to be referenced crossing goroutines. A goroutine can access or modify the value parts hosted on a memory block allocated on the stack of the goroutine without using any data synchronization techniques.
</div>
<p></p>
<div class="tmd-usual">
<span class="tmd-italic">(About which memory blocks will be allocated on stack, Please reand the "Stack and Escape Analysis" chapter in the </span><a href="https://go101.org/optimizations/101.html"><span class="tmd-italic">Go Optimizations 101</span></a><span class="tmd-italic"> book.)</span>
</div>
<p></p>
<p></p>
<div class="tmd-usual">
Heap is a singleton in each program. It is a virtual concept. If a memory block is not allocated on any goroutine stack, then we say the memory block is allocated on heap. Value parts hosted on memory blocks allocated on heap can be used by multiple goroutines. In other words, they can be used concurrently. Their uses should be synchronized when needed.
</div>
<p></p>
<div class="tmd-usual">
Heap is a conservative place to allocate memory blocks on. If compilers detect a memory block will be referenced crossing goroutines or can't easily confirm whether or not the memory block is safe to be put on the stack of a goroutine, then the memory block will be allocated on heap at run time. This means some values which can be safely allocated on stacks may also be allocated on heap.
</div>
<p></p>
<p></p>
<div class="tmd-usual">
In fact, stacks are not essential for Go programs. Go compiler/runtime can allocate all memory block on heap. Supporting stacks is just to make Go programs run more efficiently:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
allocating memory blocks on stacks is much faster than on heap.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
memory blocks allocated on a stack don't need to be garbage collected.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
stack memory blocks are more CPU cache friendly than heap ones.
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
If a memory block is allocated somewhere, we can also say the value parts hosted on the memory block are allocated on the same place.
</div>
<p></p>
<div class="tmd-usual">
If some value parts of a local variable declared in a function is allocated on heap, we can say the value parts (and the variable) escape to heap. By using Go Toolchain, we can run <code class="tmd-code-span">go build -gcflags -m</code> to check which local values (value parts) will escape to heap at run time. As mentioned above, the current escape analyzer in the standard Go compiler is still not perfect, many local value parts can be allocated on stacks safely will still escape to heap.
</div>
<p></p>
<div class="tmd-usual">
An active value part allocated on heap still in use must be referenced by at least one value part allocated on a stack. If a value escaping to heap is a declared local variable, and assume its type is <code class="tmd-code-span">T</code>, Go runtime will create (a memory block for) an implicit pointer of type <code class="tmd-code-span">*T</code> on the stack of the current goroutine. The value of the pointer stores the address of the memory block allocated for the variable on heap (a.k.a., the address of the local variable of type <code class="tmd-code-span">T</code>). Go compiler will also replace all uses of the variable with dereferences of the pointer value at compile time. The <code class="tmd-code-span">*T</code> pointer value on stack may be marked as dead since a later time, so the reference relation from it to the <code class="tmd-code-span">T</code> value on heap will disappear. The reference relation from the <code class="tmd-code-span">*T</code> value on stack to the <code class="tmd-code-span">T</code> value on heap plays an important role in the garbage collection process which will be described below.
</div>
<p></p>
<div class="tmd-usual">
Similarly, we can view each package-level variable is allocated on heap, and the variable is referenced by an implicit pointer which is allocated on a global memory zone. In fact, the implicit pointer references the direct part of the package-level variable, and the direct part of the variable references some other value parts.
</div>
<p></p>
<div class="tmd-usual">
A memory block allocated on heap may be referenced by multiple value parts allocated on different stacks at the same time.
</div>
<p></p>
<div class="tmd-usual">
Some facts:
</div>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
if a field of a struct value escapes to heap, then the whole struct value will also escape to heap.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
if an element of an array value escapes to heap, then the whole array value will also escape to heap.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
if an element of a slice value escapes to heap, then all the elements of the slice will also escape to heap.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
if a value (part) <code class="tmd-code-span">v</code> is referenced by a value (part) which escapes to heap, then the value (part) <code class="tmd-code-span">v</code> will also escape to heap.
</div>
</li>
</ul>
<p></p>
<div class="tmd-usual">
A memory block created by calling <code class="tmd-code-span">new</code> function may be allocated on heap or stacks. This is different to C++.
</div>
<p></p>
<div class="tmd-usual">
When the size of a goroutine stack changes (for stack growth or shrinkage), a new memory segment will be allocated for the stack. So the memory blocks allocated on the stack will very likely be moved, or their addresses will change. Consequently, the pointers, which must be also allocated on the stack, referencing these memory blocks also need to be modified accordingly. The following is such an example.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

// The following directive is to prevent
// calls to the function f being inlined.
//go:noinline
func f(i int) byte {
	var a [1&lt;&lt;20]byte // make stack grow
	return a[i]
}

func main(){
	var x int
	println(&amp;x)
	f(100)
	println(&amp;x)
}
</code></pre>
<p></p>
<div class="tmd-usual">
We will find that the two printed addresses are different (as of the standard Go compiler v1.25.n).
</div>
<p></p>
<p></p>
<h3 id="when-can-collect" class="tmd-header-3">
When Can a Memory Block Be Collected?
</h3>
<p></p>
<div class="tmd-usual">
Memory blocks allocated for direct parts of package-level variables will never be collected.
</div>
<p></p>
<div class="tmd-usual">
The stack of a goroutine will be collected as a whole when the goroutine exits. So there is no need to collect the memory blocks allocated on stacks, individually, one by one. Stacks are not collected by the garbage collector.
</div>
<p></p>
<div class="tmd-usual">
For a memory block allocated on heap, it can be safely collected only if it is no longer referenced (either directly or indirectly) by all the value parts allocated on goroutine stacks and the global memory zone. We call such memory blocks as unused memory blocks. Unused memory blocks on heap will be collected by the garbage collector.
</div>
<p></p>
<div class="tmd-usual">
Here is an example to show when some memory blocks can be collected:
</div>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

var p *int

func main() {
	done := make(chan bool)
	// "done" will be used in main and the following
	// new goroutine, so it will be allocated on heap.

	go func() {
		x, y, z := 123, 456, 789
		_ = z  // z can be allocated on stack safely.
		p = &amp;x // For x and y are both ever referenced
		p = &amp;y // by the global p, so they will be both
		       // allocated on heap.

		// Now, x is not referenced by anyone, so
		// its memory block can be collected now.

		p = nil
		// Now, y is also not referenced by anyone,
		// so its memory block can be collected now.

		done &lt;- true
	}()

	&lt;-done
	// Now the above goroutine exits, the done channel
	// is not used any more, a smart compiler may
	// think it can be collected now.

	// ...
}
</code></pre>
<p></p>
<div class="tmd-usual">
Sometimes, smart compilers, such as the standard Go compiler, may make some optimizations so that some references are removed earlier than we expect. Here is such an example.
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"

func main() {
	// Assume the length of the slice is so large
	// that its elements must be allocated on heap.
	bs := make([]byte, 1 &lt;&lt; 31)

	// A smart compiler can detect that the
	// underlying part of the slice bs will never be
	// used later, so that the underlying part of the
	// slice bs can be garbage collected safely now.

	fmt.Println(len(bs))
}
</code></pre>
<p></p>
<div class="tmd-usual">
Please read <a href="value-part.html">value parts</a> to learn the internal structures of slice values.
</div>
<p></p>
<div class="tmd-usual">
By the way, sometimes, we may hope the slice <code class="tmd-code-span">bs</code> is guaranteed to not being garbage collected until <code class="tmd-code-span">fmt.Println</code> is called, then we can use a <code class="tmd-code-span">runtime.KeepAlive</code> function call to tell garbage collectors that the slice <code class="tmd-code-span">bs</code> and the value parts referenced by it are still in use.
</div>
<p></p>
<div class="tmd-usual">
For example,
</div>
<p></p>
<pre class="tmd-code line-numbers">
<code class="language-go">package main

import "fmt"
import "runtime"

func main() {
	bs := make([]int, 1000000)

	fmt.Println(len(bs))

	// A runtime.KeepAlive(bs) call is also
	// okay for this specified example.
	runtime.KeepAlive(&amp;bs)
}
</code></pre>
<p></p>
<h3 id="how-to-detect" class="tmd-header-3">
How Are Unused Memory Blocks Detected?
</h3>
<p></p>
<div class="tmd-usual">
The current standard Go compiler (v1.25.n) uses a concurrent, tri-color, mark-sweep garbage collector. Here this article will only make a simple explanation for the algorithm.
</div>
<p></p>
<div class="tmd-usual">
A garbage collection (GC) process is divided into two phases, the mark phase and the sweep phase. In the mark phase, the collector (a group of goroutines actually) uses the tri-color algorithm to analyze which memory blocks are unused.
</div>
<p></p>
<div class="tmd-usual">
The following quote is taken from <a href="https://blog.golang.org/go15gc">a Go blog article</a> and is modified a bit to make it clearer.
</div>
<p></p>
<p></p>
<div class="tmd-quotation">
<div class="tmd-usual">
At the start of a GC cycle all heap memory blocks are white. The GC visits all roots, which are objects directly accessible by the application such as globals and things on the stack, and colors these grey. The GC then chooses a grey object, blackens it, and then scans it for pointers to other objects. When this scan finds a pointer to a white memory block, it turns that object grey. This process repeats until there are no more grey objects. At this point, white (heap) memory blocks are known to be unreachable and can be reused.
</div>
</div>
<p></p>
<div class="tmd-usual">
<span class="tmd-italic">(About why the algorithm uses three colors instead of two colors, please search "write barrier golang" for details. Here only provides two references: </span><a href="https://github.com/golang/proposal/blob/master/design/17503-eliminate-rescan.md"><span class="tmd-italic">eliminate STW stack re-scanning</span></a><span class="tmd-italic"> and </span><a href="https://golang.org/src/runtime/mbarrier.go"><span class="tmd-italic">mbarrier.go</span></a><span class="tmd-italic">.)</span>
</div>
<p></p>
<p></p>
<div class="tmd-usual">
In the sweep phase, the marked unused memory blocks will be collected.
</div>
<p></p>
<div class="tmd-usual">
An unused memory block may not be released to OS immediately after it is collected, so that it can be reused for new some value parts. Don't worry, the official Go runtime is much less memory greedy than most Java runtimes.
</div>
<p></p>
<div class="tmd-usual">
The GC algorithm is a non-compacting one, so it will not move memory blocks to rearrange them.
</div>
<p></p>
<h3 id="when-to-collect" class="tmd-header-3">
When Will a New Garbage Collection Process Start?
</h3>
<p></p>
<div class="tmd-usual">
Garbage collection processes will consume much CPU resources and some memory resources. So there is not always a garbage collection process in running. A new garbage collection process will be only triggered when some run-time metrics reach certain conditions. How the conditions are defined is a garbage collection pacer problem.
</div>
<p></p>
<div class="tmd-usual">
The garbage collection pacer implementation of the official standard Go runtime is still being improved from version to version. So it is hard to describe the implementation precisely and keep the descriptions up-to-date at the same time. Here, I just list some reference articles on this topic:
</div>
<p></p>
<ul class="tmd-list">
<li class="tmd-list-item">
<div class="tmd-usual">
About <a href="https://golang.org/pkg/runtime/#hdr-Environment_Variables">the <code class="tmd-code-span">GOGC</code> and <code class="tmd-code-span">GOMEMLIMIT</code> environment variables</a> (note that the <code class="tmd-code-span">GOMEMLIMIT</code> environment variable is only supported since Go 1.19).
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
<a href="https://go.dev/doc/gc-guide">A Guide to the Go Garbage Collector</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
<a href="https://github.com/golang/proposal/blob/master/design/44167-gc-pacer-redesign.md">GC Pacer Redesign</a>.
</div>
</li>
<li class="tmd-list-item">
<div class="tmd-usual">
The "Garbage Collection" chapter of my <a href="https://go101.org/optimizations/101.html">Go Optimizations 101</a> book (it is a paid book).
</div>
</li>
</ul>
<p></p>
<p></p>
</div>
